1 /* 2 * Copyright (C) 2012 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.util.concurrent.testing; 18 19 import com.google.common.annotations.Beta; 20 import com.google.common.collect.ImmutableList; 21 import com.google.common.primitives.Longs; 22 import com.google.common.util.concurrent.AbstractFuture; 23 import com.google.common.util.concurrent.AbstractListeningExecutorService; 24 import com.google.common.util.concurrent.ListenableScheduledFuture; 25 import com.google.common.util.concurrent.ListeningScheduledExecutorService; 26 import com.google.common.util.concurrent.MoreExecutors; 27 28 import java.util.List; 29 import java.util.concurrent.Callable; 30 import java.util.concurrent.Delayed; 31 import java.util.concurrent.ScheduledFuture; 32 import java.util.concurrent.TimeUnit; 33 34 /** 35 * Factory methods for {@link ExecutorService} for testing. 36 * 37 * @author Chris Nokleberg 38 * @since 14.0 39 */ 40 @Beta 41 public final class TestingExecutors { 42 private TestingExecutors() {} 43 44 /** 45 * Returns a {@link ScheduledExecutorService} that never executes anything. 46 * 47 * <p>The {@code shutdownNow} method of the returned executor always returns an empty list despite 48 * the fact that everything is still technically awaiting execution. 49 * The {@code getDelay} method of any {@link ScheduledFuture} returned by the executor will always 50 * return the max long value instead of the time until the user-specified delay. 51 */ 52 public static ListeningScheduledExecutorService noOpScheduledExecutor() { 53 return new NoOpScheduledExecutorService(); 54 } 55 56 /** 57 * Creates a scheduled executor service that runs each task in the thread 58 * that invokes {@code execute/submit/schedule}, as in 59 * {@link CallerRunsPolicy}. This applies both to individually submitted 60 * tasks and to collections of tasks submitted via {@code invokeAll}, 61 * {@code invokeAny}, {@code schedule}, {@code scheduleAtFixedRate}, and 62 * {@code scheduleWithFixedDelay}. In the case of tasks submitted by 63 * {@code invokeAll} or {@code invokeAny}, tasks will run serially on the 64 * calling thread. Tasks are run to completion before a {@code Future} is 65 * returned to the caller (unless the executor has been shutdown). 66 * 67 * <p>The returned executor is backed by the executor returned by 68 * {@link MoreExecutors#newDirectExecutorService} and subject to the same 69 * constraints. 70 * 71 * <p>Although all tasks are immediately executed in the thread that 72 * submitted the task, this {@code ExecutorService} imposes a small 73 * locking overhead on each task submission in order to implement shutdown 74 * and termination behavior. 75 * 76 * <p>Because of the nature of single-thread execution, the methods 77 * {@code scheduleAtFixedRate} and {@code scheduleWithFixedDelay} are not 78 * supported by this class and will throw an UnsupportedOperationException. 79 * 80 * <p>The implementation deviates from the {@code ExecutorService} 81 * specification with regards to the {@code shutdownNow} method. First, 82 * "best-effort" with regards to canceling running tasks is implemented 83 * as "no-effort". No interrupts or other attempts are made to stop 84 * threads executing tasks. Second, the returned list will always be empty, 85 * as any submitted task is considered to have started execution. 86 * This applies also to tasks given to {@code invokeAll} or {@code invokeAny} 87 * which are pending serial execution, even the subset of the tasks that 88 * have not yet started execution. It is unclear from the 89 * {@code ExecutorService} specification if these should be included, and 90 * it's much easier to implement the interpretation that they not be. 91 * Finally, a call to {@code shutdown} or {@code shutdownNow} may result 92 * in concurrent calls to {@code invokeAll/invokeAny} throwing 93 * RejectedExecutionException, although a subset of the tasks may already 94 * have been executed. 95 * 96 * @since 15.0 97 */ 98 public static SameThreadScheduledExecutorService sameThreadScheduledExecutor() { 99 return new SameThreadScheduledExecutorService(); 100 } 101 102 private static final class NoOpScheduledExecutorService 103 extends AbstractListeningExecutorService implements ListeningScheduledExecutorService { 104 105 private volatile boolean shutdown; 106 107 @Override public void shutdown() { 108 shutdown = true; 109 } 110 111 @Override public List<Runnable> shutdownNow() { 112 shutdown(); 113 return ImmutableList.of(); 114 } 115 116 @Override public boolean isShutdown() { 117 return shutdown; 118 } 119 120 @Override public boolean isTerminated() { 121 return shutdown; 122 } 123 124 @Override public boolean awaitTermination(long timeout, TimeUnit unit) { 125 return true; 126 } 127 128 @Override public void execute(Runnable runnable) {} 129 130 @Override public <V> ListenableScheduledFuture<V> schedule( 131 Callable<V> callable, long delay, TimeUnit unit) { 132 return NeverScheduledFuture.create(); 133 } 134 135 @Override public ListenableScheduledFuture<?> schedule( 136 Runnable command, long delay, TimeUnit unit) { 137 return NeverScheduledFuture.create(); 138 } 139 140 @Override public ListenableScheduledFuture<?> scheduleAtFixedRate( 141 Runnable command, long initialDelay, long period, TimeUnit unit) { 142 return NeverScheduledFuture.create(); 143 } 144 145 @Override public ListenableScheduledFuture<?> scheduleWithFixedDelay( 146 Runnable command, long initialDelay, long delay, TimeUnit unit) { 147 return NeverScheduledFuture.create(); 148 } 149 150 private static class NeverScheduledFuture<V> 151 extends AbstractFuture<V> implements ListenableScheduledFuture<V> { 152 153 static <V> NeverScheduledFuture<V> create() { 154 return new NeverScheduledFuture<V>(); 155 } 156 157 @Override public long getDelay(TimeUnit unit) { 158 return Long.MAX_VALUE; 159 } 160 161 @Override public int compareTo(Delayed other) { 162 return Longs.compare(getDelay(TimeUnit.NANOSECONDS), other.getDelay(TimeUnit.NANOSECONDS)); 163 } 164 } 165 } 166 }